﻿using System;
using System.Collections.Generic;
using System.Windows.Forms;
using Bule.Malbilden.Data;
using Bule.Components.FilteredSelectionList;
using Bule.Components.InputBox;
using Bule.Malbilden.Domain;
using Bule.Malbilden.Util;
using System.Globalization;

namespace Bule.Malbilden.Forms
{
    public partial class MealView : Form
    {
        private Meal currentMeal;
        private IPersistentContext context;
        private IListViewItemListCreator listCreator;
        private bool hasMadeChanges;

        public MealView()
        {
            InitializeComponent();
        }

        private void CreateNewContext()
        {
            if (context != null)
                context.Dispose();

            context = new PersistentContext();
            listCreator = new ListViewItemListCreator(context);
        }

        private void cancelButton_Click(object sender, EventArgs e)
        {
            this.DialogResult = DialogResult.Cancel;
            this.Close();
        }

        private void changeButton_Click(object sender, EventArgs e)
        {
            bool wasDialogCompleted = PromptUserToSaveChanges();

            if (wasDialogCompleted)
                ChangeMeal();
        }

        private void renameButton_Click(object sender, EventArgs e)
        {
            RenameMeal();
        }

        private void newButton_Click(object sender, EventArgs e)
        {
            bool wasDialogCompleted = PromptUserToSaveChanges();

            if (wasDialogCompleted)
                CreateNewMeal();
        }

        private void removeButton_Click(object sender, EventArgs e)
        {
            RemoveMeal();
        }

        private void foodList_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (foodList.SelectedItems.Count > 0)
                removeFoodButton.Enabled = true;
            else
                removeFoodButton.Enabled = false;
        }

        private void addFoodButton_Click(object sender, EventArgs e)
        {
            AddIngredient();
        }

        private void removeFoodButton_Click(object sender, EventArgs e)
        {
            RemoveIngredient();
        }

        private void saveButton_Click(object sender, EventArgs e)
        {
            SaveMeal();
        }

        private void foodList_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            ChangeFoodWeight();
        }

        private void closeButton_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void MealView_FormClosing(object sender, FormClosingEventArgs e)
        {
            bool wasDialogCompleted = PromptUserToSaveChanges();
            
            if (!wasDialogCompleted)
                e.Cancel = true;
        }

        private void portionCountTextbox_KeyPress(object sender, KeyPressEventArgs e)
        {
            e.Handled = !InputFilter.GivesValidNumeric(e.KeyChar, ((TextBox)sender).Text);
        }

        private void portionNameTextbox_Leave(object sender, EventArgs e)
        {
            currentMeal.PortionName = portionNameTextbox.Text;
        }

        private void portionCountTextbox_Leave(object sender, EventArgs e)
        {
            currentMeal.PortionCount = Convert.ToDouble(portionCountTextbox.Text, CultureInfo.CurrentCulture);
        }

        private void InitializeFormFromMeal(Meal currentMeal)
        {
            foodList.Items.Clear();

            nameTextbox.Text = currentMeal.Name;
            portionNameTextbox.Text = currentMeal.PortionName;
            portionCountTextbox.Text = currentMeal.PortionCount.ToString();

            foreach (EatenItem foodItem in currentMeal.Food)
            {
                ListViewItem listItem = new ListViewItem(foodItem.Name);
                listItem.SubItems.Add(Convert.ToString(foodItem.Weight));
                listItem.Tag = foodItem;
                foodList.Items.Add(listItem);
            }
        }

        private void UpdateControlEnabledState()
        {
            bool hasCurrentMeal = (currentMeal != null);
            bool hasAllNeededData = !string.IsNullOrEmpty(portionCountTextbox.Text) &&
                !string.IsNullOrEmpty(portionNameTextbox.Text);

            saveButton.Enabled = hasCurrentMeal && hasAllNeededData;
            addFoodButton.Enabled = hasCurrentMeal;
            portionNameTextbox.Enabled = hasCurrentMeal;
            portionCountTextbox.Enabled = hasCurrentMeal;
            renameButton.Enabled = hasCurrentMeal;
            removeMealButton.Enabled = hasCurrentMeal;
        }

        private void RemoveMeal()
        {
            foreach (var ingredient in currentMeal.Food)
                context.Remove(ingredient);

            context.Remove(currentMeal);

            currentMeal = null;
        }

        private void SaveMeal()
        {
            foreach (var ingredient in currentMeal.Food)
                context.Save(ingredient);

            context.Save(currentMeal);
        }

        private void AddIngredient()
        {
            IEatable product = PromptUserForIngredient();

            if (product != null)
            {
                double weight = PromptUserForWeight(product, product.PortionSize);

                if (weight > 0)
                {
                    IEaten ingredient = new EatenItem(product, weight);
                    currentMeal.AddFood(ingredient);
                }
            }

            InitializeFormFromMeal(currentMeal);

            hasMadeChanges = true;
        }

        private void RemoveIngredient()
        {
            IEaten ingredient = GetSelectedIngredient();

            if (ingredient != null)
            {
                currentMeal.RemoveFood(ingredient);
                InitializeFormFromMeal(currentMeal);
            }

            hasMadeChanges = true;
        }

        private IEaten GetSelectedIngredient()
        {
            IEaten selected = null;

            if (foodList.SelectedItems.Count > 0)
                selected = (IEaten)foodList.SelectedItems[0].Tag;

            return selected;
        }

        private void CreateNewMeal()
        {
            CreateNewContext();
            hasMadeChanges = false;

            string name = PromptUserForMealName();

            if (!string.IsNullOrEmpty(name))
                currentMeal = new Meal() { Name = name, PortionCount = 1, PortionName = "portion" };

            InitializeFormFromMeal(currentMeal);
            UpdateControlEnabledState();
        }

        private void RenameMeal()
        {
            string name = PromptUserForMealName();

            if (!string.IsNullOrEmpty(name))
                currentMeal.Name = name;

            InitializeFormFromMeal(currentMeal);
            UpdateControlEnabledState();

            hasMadeChanges = true;
        }

        private void ChangeFoodWeight()
        {
            IEaten ingredient = GetSelectedIngredient();

            double newWeight = PromptUserForWeight(ingredient.Food, ingredient.Weight);

            if (newWeight > 0)
                ingredient.Weight = newWeight;

            InitializeFormFromMeal(currentMeal);

            hasMadeChanges = true;
        }

        private string PromptUserForMealName()
        {
            InputBox inputbox = new InputBox("Ange namn", "Ange namn för måltiden:", false);
            DialogResult result = inputbox.ShowDialog();

            String newName = "";

            if (result == DialogResult.OK && !string.IsNullOrEmpty(inputbox.Input))
                newName = inputbox.Input;

            return newName;
        }

        private double PromptUserForWeight(IEatable product, double defaultWeight)
        {
            double weight = -1;

            WeightPortionsInputbox amountBox = new WeightPortionsInputbox(product.PortionName, product.PortionSize, defaultWeight);
            DialogResult result = amountBox.ShowDialog();

            if (result == DialogResult.OK && amountBox.Weight > 0)
                weight = amountBox.Weight;

            return weight;
        }

        private IEatable PromptUserForIngredient()
        {
            IEatable ingredient = null;
            List<ListViewItem> itemList = listCreator.CreateFoodProductList();

            FilteredSelectionListDialog selector = new FilteredSelectionListDialog("Välj livsmedel", itemList);
            DialogResult result = selector.ShowDialog();

            if (result == DialogResult.OK && selector.SelectedItem != null)
                ingredient = (FoodProduct)selector.SelectedItem.Tag;

            return ingredient;
        }

        private void ChangeMeal()
        {
            CreateNewContext();
            hasMadeChanges = false;

            Meal meal = PromptUserForMeal();

            if (meal != null)
                currentMeal = meal;

            InitializeFormFromMeal(currentMeal);
            UpdateControlEnabledState();
        }

        private Meal PromptUserForMeal()
        {
            Meal selectedMeal = null;
            List<ListViewItem> items = listCreator.CreateMealList();
            FilteredSelectionListDialog selector = new FilteredSelectionListDialog("Välj måltid att redigera", items);

            DialogResult result = selector.ShowDialog();

            if (result == DialogResult.OK && selector.SelectedItem != null)
                selectedMeal = (Meal)selector.SelectedItem.Tag;

            return selectedMeal;
        }

        // Returns true if the user selected anything but cancel, false if the user cancelled the dialog.
        private bool PromptUserToSaveChanges()
        {
            bool wasSaveDialogCompleted = true;

            if (currentMeal != null && hasMadeChanges)
            {
                DialogResult result = MessageBox.Show("Vill du spara ändringarna?", "Spara", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);

                if (result == DialogResult.Cancel)
                    wasSaveDialogCompleted = false;
                else if (result == DialogResult.Yes)
                    SaveMeal();
            }

            return wasSaveDialogCompleted;
        }
    }
}